# -*- coding: UTF-8 -*-
__author__ = 'kidozh'

import tornado.web
import tornado
import tornado.websocket
from db import connectHandler, database
from contrib.admin.models import *
import psutil
import platform
import json
from contrib.admin.appModel import modelFinder


class BaseHandler(tornado.web.RequestHandler):
    # peewee
    def prepare(self):
        database.connect()
        return super(BaseHandler, self).prepare()

    def on_finish(self):
        if not database.is_closed():
            database.close()
        return super(BaseHandler, self).on_finish()

    def get_current_user(self):
        # check current user privilege
        username = self.get_secure_cookie("username")
        # init database connect

        # queryObj = connectInstance.query(adminUser).filter(adminUser.username == username)
        if admin.select().where(admin.username == username).exists():
            # there is a username
            aimUser = admin.select().where(admin.username == username).get()
            if aimUser.isStaff:
                # successfully
                self._current_user = aimUser
                return aimUser

        return None

    def write_error(self, status_code, **kwargs):
        args = locals()
        args.pop('self')
        self.render('contrib/admin/error.html', **args)


class authRequestHandler(BaseHandler):
    def get(self, *args, **kwargs):
        # self.render('portal/index.html')
        self.render('contrib/admin/login.html')

    def post(self, *args, **kwargs):
        username = self.get_argument('username')
        password = self.get_argument('password')
        self.username = username
        self.password = password

        # make sure bcrypt could encrypt this password
        if len(password) <= 8 or len(password) >= 21:
            self._reason = '密码应为8-20位'
            self.write_error(500)
        else:
            # auth
            # rewrite by peewee
            # queryObj = connectInstance.query(adminUser).filter(adminUser.username == username)
            # print connectInstance.query(adminUser).filter_by(username=username).count()

            # using peewee
            if admin.select().where(admin.username == username).count():
                # username exist
                aimAdmin = admin.select().where(admin.username == username).get()

                # auth password
                if aimAdmin.authPassword(password):
                    # successfully login
                    self.set_secure_cookie('username', username)
                    # URL configuration
                    from conf import setting
                    from conf.urls import urlPackage
                    Setting = setting()
                    Setting._setup()
                    urlMapper = urlPackage(Setting._wrapped.ROOT_URLCONF)
                    # check permission
                    # auth permission
                    if not aimAdmin.isStaff:
                        self._reason = '您的账号目前无法访问仪表盘，请联系管理员。'
                        self.write_error(404)
                    # redirect
                    self.redirect(urlMapper.get_url_by_handler('contrib.admin.view.adminManageHandler'))
                else:
                    self._reason = '用户名或者密码错误'
                    self.write_error(404)
            else:
                self._reason = '用户名或者密码错误'
                self.write_error(404)

            self.render('contrib/admin/login.html', **args)

    def write_error(self, status_code, **kwargs):
        args = locals()
        args.pop('self')
        self.render('contrib/admin/loginError.html', **args)


class adminManageHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        import psutil
        import platform
        # cpu info
        logicalCPU = psutil.cpu_count(logical=True)
        physicsCPU = psutil.cpu_count(logical=False)

        # platform uname
        (system, node, release, version, machine, processor) = platform.uname()

        # cpu usage
        usedCPURate = psutil.cpu_percent(interval=1, percpu=False)

        # memory info
        mem = psutil.virtual_memory()

        # start time
        startTime = psutil.boot_time()

        # network statistics
        network = psutil.net_io_counters(pernic=False)

        from conf.urls import urlPackage
        from conf import setting
        Setting = setting()
        Setting._setup()

        logFileExist = getattr(Setting._wrapped, 'LOGFILE', False)

        modelsFinder = modelFinder()
        # a tuple containing three element : app,className,class
        modelsList = modelsFinder.getInstalledModel()

        # fill render parameter
        args = locals()
        args.pop('self')
        self.render('contrib/admin/manage.html', **args)


# a HTTP handler for status api
class statusAPIHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        # import module for neccessary
        import sysStatus
        import tornado.escape

        sysInfo = sysStatus.PsutilStats()
        infoDict = sysInfo.loadSummaryData()
        jsonString = tornado.escape.json_encode(infoDict)
        self.write(jsonString)
        self.finish()


# advanced websocket server
class statusWebsocketAPIHandler(tornado.websocket.WebSocketHandler):
    '''
    this socketHandler is aimed to reduce stress from query system's status
    '''
    clients = []
    cache_size = 200

    # you should change it by yourself
    def check_origin(self, origin):
        return True

    def open(self, *args, **kwargs):
        '''
        make auth then add to client
        :param args:
        :param kwargs:
        :return:
        '''
        import sysStatus
        import tornado.escape

        sysInfo = sysStatus.PsutilStats()
        infoDict = sysInfo.loadSummaryData()
        jsonString = tornado.escape.json_encode(infoDict)
        self.write_message(jsonString)
        # directly get info
        self.clients.append(self)

    def on_message(self, message):

        import sysStatus
        import tornado.escape

        sysInfo = sysStatus.PsutilStats()
        infoDict = sysInfo.loadSummaryData()
        jsonString = tornado.escape.json_encode(infoDict)
        self.write_message(jsonString)

    def on_close(self):
        # msgDict = {'result': 3, 'response-Text': 'GoodBye~', 'response-Time': ''}
        # 0 : connect start
        # 1 : right ,give answer
        # 2 : wrong , give reason
        # 3 : shutdown websocket
        # response Text
        # self.write_message(json.dumps(msgDict))
        for client in self.clients:
            if client == self:
                self.clients.remove(client)
            else:
                pass

    @classmethod
    def update_cache(cls):
        # cls.cache.append(chat)
        if len(cls.cache) > cls.cache_size:
            cls.cache = cls.cache[-cls.cache_size:]


class appModelManger(BaseHandler):

    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        modelName,action = args


if __name__ == '__main__':
    # from db import base,connect
    # base.metadata.create_all()
    '''connectDB = connectHandler()
    connectSession = connectDB.gennerateSession
    connectInstance = connectSession()
    newUser = adminUser('kidozh','8520967123')
    newUser.create_table()
    connectInstance.add(newUser)
    connectInstance.commit()
    connectInstance.close()
    '''

    # gennerate super-admin user
    from db import database

    database.connect()
    try:
        database.create_tables([admin])
    except:
        pass
    new_adminUser = admin(username='kidozh', password='8520967123',isStaff=True,isAdmin=True)
    new_adminUser.save()
